/*
 * Copyright 2012 Niklas Rehfeld
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.madpie.converters;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.validation.SchemaFactory;
import org.madpie.schemas.ComponentClassType;
import org.madpie.schemas.ComponentType;
import org.madpie.schemas.Machine;
import org.madpie.util.SchemaUtils;
import org.xml.sax.SAXException;

/**
 *
 * @author Niklas Rehfeld
 */
public class Lspci
{

    private JAXBContext jbc;
    private Machine machine;
    private List<ComponentType> components;

    /**
     * The arguments are as follows: <ol> <li> inputfile </li> <li> outputfile
     * </li> </ol> where either file can be '-' to read or write standard input
     * /output.
     *
     * @param args the command line arguments
     *
     */
    public static void main(String[] args) throws JAXBException, IOException
    {
        Logger.getLogger(Lspci.class.getName()).setLevel(Level.ALL);
        if (args.length < 2)
        {
            printUsage();
        }
        Machine m = null;
        //output config
        OutputStream os = null;
        if (args[1].equals("-"))
        {
            os = System.out;
            m = SchemaUtils.ReadHardwareFile(null);
        }
        else
        {
            File of = new File(args[1]);
            m = SchemaUtils.ReadHardwareFile(of);
            os = new FileOutputStream(of);
        }

        InputStream is = null;
        if (args[0].equals("-"))
        {
            is = System.in;
        }
        else
        {
            is = new FileInputStream(args[0]);
        }
        Lspci converter = new Lspci(m);
        converter.readInput(is);
        converter.writeXMLFile(os);

    }

    public Lspci(Machine m) throws JAXBException
    {
        jbc = JAXBContext.newInstance("org.madpie.schemas");
        machine = m;
        components = machine.getComponent(); //should never return null, I hope
    }

    /**
     * Reads the output from
     * <code>lspci -vvmmnn</code>
     *
     * @param is
     */
    public void readInput(InputStream is)
    {
        if (is == null)
        {
            throw new IllegalArgumentException("No output stream given.");
        }

        Scanner s = new Scanner(is);
        String line;
        ComponentType c = new ComponentType();
        while (s.hasNextLine())
        {
            line = s.nextLine();
            if (line.trim().isEmpty())
            {
                components.add(c);
                c = new ComponentType();
                continue;
            }
            String[] parts = line.split(":");
            if (parts.length < 2)
            {
                continue;
            }
            String label = parts[0].trim();
            String value = parts[1].trim();
            if (label.equalsIgnoreCase("Class"))
            {
                if (value.startsWith("Network") || value.startsWith("Ethernet"))
                {
                    c.setClazz(ComponentClassType.NETWORK);
                }
                else if (value.startsWith("Audio"))
                {
                    c.setClazz(ComponentClassType.SOUND);
                }
                else if (value.startsWith("VGA"))
                {
                    c.setClazz(ComponentClassType.GRAPHICS);
                }
                else
                {
                    c.setClazz(ComponentClassType.OTHER);
                    //should really handle a couple of other classes here..
                }
            }
            else if (label.equalsIgnoreCase("Vendor"))
            {
                c.setVendor(value);
            }
            else if (label.equalsIgnoreCase("Device"))
            {
                c.setName(value);
            }
        }
        //this is so unknown names don't get cleaned up. 
        if (c.getName() == null || c.getName().trim().isEmpty())
        {
            c.setName("Unknown");
        }
    }

    public void writeXMLFile(OutputStream os) throws JAXBException
    {
        Marshaller marsh = jbc.createMarshaller();
        marsh.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marsh.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
        try
        {
            marsh.setSchema(
                    SchemaFactory.newInstance(
                    XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(
                    new File("source/xml/hw.xsd")));
        } catch (SAXException ex)
        {
            Logger.getLogger(Lspci.class.getName()).log(Level.SEVERE,
                    "Couldn't open schema: ", ex);
        }
        Logger.getLogger(Lspci.class.getName()).log(Level.INFO,
                "Writing out using schema: {0}", marsh.getSchema());
        marsh.marshal(SchemaUtils.cleanMachine(machine), os);
    }

    public static void printUsage()
    {
        System.out.println("Usage:");
        System.out.println("\t lspci2xml input output");
        System.out.println("\t where input can be a file or "
                + "'-' for standard input");
    }
}
